package net.bat.dao;

import java.lang.reflect.Field;
import java.util.Date;
import java.util.Map;

import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.PersistenceContext;

import net.bat.entity.IdEntity;
import net.bat.entity.LOper;
import net.bat.service.account.ShiroDbRealm.ShiroUser;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.BeanWrapperImpl;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;

@Repository
@Transactional(value = "transactionManager", noRollbackFor = { NoResultException.class })
public class UserDAO extends BaseJpaDao {
	public enum Action {
		ADD, REMOVE, UPDATE
	}

	private Gson gson = new GsonBuilder().disableHtmlEscaping().create();

	@PersistenceContext(unitName = "entityManagerFactory")
	private EntityManager entityManager;

	@Override
	public EntityManager getEntityManager() {
		// TODO Auto-generated method stub
		return entityManager;
	}

	public <T extends IdEntity> T load(Class<T> entity, Map<String, Object> rmap) throws Exception {
		Object id = rmap.get("id");
		T eo = null;
		if (id != null) {
			eo = find(entity, Long.parseLong(id.toString()));
		}
		if (eo == null) {
			eo = entity.newInstance();
		}
		setEntityByMap(eo, rmap);
		return eo;
	}

	private void setEntityByMap(IdEntity eo, Map<String, Object> rmap) throws NoSuchFieldException, SecurityException {
		// 验证rmap中值的类型，需要对日期型进行特殊处理
		BeanWrapperImpl beanWrapper = new BeanWrapperImpl(eo);
		rmap.remove("id");
		Class cls = eo.getClass();
		for (Map.Entry<String, Object> entry : rmap.entrySet()) {
			String fn = entry.getKey();
			Field f = null;
			try {
				f = cls.getDeclaredField(fn);
			} catch (Exception e) {
				continue;
			}
			Object fval = entry.getValue();
			Class<?> fcl = f.getType();
			if ((fval != null) && !fcl.isAssignableFrom(fval.getClass())) {
				if (fcl.isAssignableFrom(Date.class)) {
					rmap.put(fn, new Date(Long.parseLong(fval.toString())));
				}
			}
		}
		beanWrapper.setPropertyValues(rmap);
	}

	public long savel(IdEntity data, Map<String, Object> rmap, boolean bRemove) {
		LOper oper = new LOper();
		oper.setEname(data.getClass().getName());
		if (data.getId() == null) {
			getEntityManager().persist(data);
			// 创建一条新的记录
			oper.setOper("A");
		} else {
			if (bRemove) {
				getEntityManager().remove(data);
				oper.setOper("R");
			} else {
				getEntityManager().merge(data);
				// 更新一条已有的记录
				oper.setOper("U");
			}
		}
		oper.setEid(data.getId());
		oper.setDtCreate(new Date());
		Subject subject = SecurityUtils.getSubject();
		ShiroUser user = (ShiroUser) subject.getPrincipal();
		oper.setUid(user.id);
		oper.setIpaddr(subject.getSession().getHost());
		// 具体操作内容
		if (rmap != null) {
			oper.setContent(gson.toJson(rmap));
		}
		save(oper);
		return data.getId();
	}

	public long savel(IdEntity data, Map<String, Object> rmap) {
		return savel(data, rmap, false);
	}

	/**
	 * 带操作日志的保存
	 * 
	 * @throws ClassNotFoundException
	 */
	@Transactional
	public <T extends IdEntity> T update(String entity_name, Long id, Map<String, Object> rmap) throws Exception {
		Class<T> entity = classForName(entity_name);
		T eo = find(entity, id);
		// entity不存在,新建之
		if (eo == null) {
			return add(entity_name, rmap);
		}
		setEntityByMap(eo, rmap);
		savel(eo, rmap);
		return eo;
	}

	@Transactional
	public <T extends IdEntity> T add(Class<T> entity, Map<String, Object> rmap) throws Exception {
		T eo = entity.newInstance();
		rmap.remove("id");
		setEntityByMap(eo, rmap);
		savel(eo, rmap);
		return eo;
	}

	@Transactional
	public <T extends IdEntity> T add(String entity_name, Map<String, Object> rmap) throws Exception {
		return add((Class<T>) classForName(entity_name), rmap);
	}

	@Transactional
	public <T extends IdEntity> void remove(String entity_name, Object[] ids) throws Exception {
		Class<T> entity = classForName(entity_name);
		Long[] lids = new Long[ids.length];
		int pos = 0;
		for (Object id : ids) {
			Long lid = Long.parseLong(id.toString());
			lids[pos++] = lid;
			savel(getEntityManager().find(entity, lid), null, true);
		}
		// delete(entity, lids);
	}

	/**
	 * @param entity
	 * @return
	 * @throws ClassNotFoundException
	 */
	public static <T extends IdEntity> Class<T> classForName(String entity) throws ClassNotFoundException {
		return (Class<T>) Class.forName(getEntityFullName(entity));
	}

	/**
	 * 补齐默认包路径全名
	 *
	 * @param entity
	 * @return
	 */
	public static String getEntityFullName(String entity) {
		if (entity.indexOf(".") == -1) {
			return "net.bat.entity." + entity;
		} else {
			return entity;
		}
	}

}
